package com.jason.common.file.word.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.jason.common.core.exception.BizException;
import lombok.extern.slf4j.Slf4j;

import java.text.NumberFormat;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 并发秒表封装
 *
 * @author gzc
 * @since 2023/10/12
 **/
@Slf4j
@SuppressWarnings("unused")
public class ConcurrentStopWatch {

    /**
     * 秒表并发集合
     */
    private final TreeMap<String, StopWatch> STOP_WATCH_MAP = new TreeMap<>(Comparator.naturalOrder());
//    private final Map<String, StopWatch> STOP_WATCH_MAP = new HashMap<>(16);
//    private final Map<String, StopWatch> STOP_WATCH_MAP = new ConcurrentHashMap<>(16);
//    private final Map<String, StopWatch> STOP_WATCH_MAP = new ConcurrentSkipListMap<>();
    /**
     * 总任务名称
     */
    private final String totalTaskName;

    public ConcurrentStopWatch(String totalTaskName) {
        Assert.notBlank(totalTaskName, "总任务名称为空");
        this.totalTaskName = totalTaskName;
    }

    public Map<String, StopWatch> getStopWatchMap() {
        return this.STOP_WATCH_MAP;
    }

    public void putAll(Map<String, StopWatch> map) {
        this.STOP_WATCH_MAP.putAll(map);
    }

    public void put(String key, StopWatch stopWatch) {
        this.STOP_WATCH_MAP.put(key, stopWatch);
    }

    /**
     * 开始任务
     *
     * @param taskName 任务名称
     */
    public void start(String taskName) {
        try {
            StopWatch stopWatch = this.STOP_WATCH_MAP.get(taskName);
            if (stopWatch == null) {
                stopWatch = new StopWatch(taskName);
                stopWatch.start(taskName);
                this.STOP_WATCH_MAP.put(taskName, stopWatch);
            } else {
                if (stopWatch.isRunning()) {
                    stopWatch.stop();
                }
            }
        } catch (Exception e) {
            throw new BizException(String.format("开始监控任务%s失败,原因:%s", taskName, e.getCause()), e);
        }
    }

    /**
     * 停止任务
     *
     * @param taskName 任务名称
     */
    public void stop(String taskName) {
        try {
            StopWatch stopWatch = this.STOP_WATCH_MAP.get(taskName);
            if (stopWatch.isRunning()) {
                stopWatch.stop();
            }
        } catch (Exception e) {
            throw new BizException(String.format("停止监控任务失败,原因:%s", e.getCause()), e);
        }
    }

    /**
     * 停止所有任务
     */
    public void stopAll() {
        try {
            this.STOP_WATCH_MAP.values().forEach(stopWatch -> {
                if (stopWatch.isRunning()) {
                    stopWatch.stop();
                }
            });
        } catch (Exception e) {
            throw new BizException(String.format("停止全部监控任务失败,原因:%s", e.getCause()), e);
        }
    }

    /**
     * 获取执行计划
     *
     * @param timeUnit 时间单位
     * @return 执行计划字符串
     */
    public String prettyPrint(TimeUnit timeUnit) {
        try {
            Assert.notNull(timeUnit, "时间单位参数为空");
            StringBuilder sb = new StringBuilder();
            if (CollUtil.isNotEmpty(this.STOP_WATCH_MAP)) {
                // 获取总耗时
                AtomicLong totalCostAtomicLong = new AtomicLong(0);
                this.STOP_WATCH_MAP.values().stream().map(StopWatch::getLastTaskInfo).forEach(item -> totalCostAtomicLong.addAndGet(item.getTime(timeUnit)));
                long totalCost = totalCostAtomicLong.longValue();
                // 拼接打印执行计划字符串
                String titleDesc = StrUtil.format("秒表名称 '{}': 运行耗时 = {} {}",
                        totalTaskName, totalCost, DateUtil.getShotName(timeUnit));
                sb.append(titleDesc).append(FileUtil.getLineSeparator());
                sb.append("---------------------------------------------").append(FileUtil.getLineSeparator());
                sb.append("   ")
                        .append(DateUtil.getShotName(timeUnit)).append("         耗时占比          任务名称")
                        .append(FileUtil.getLineSeparator());
                final NumberFormat nf = NumberFormat.getNumberInstance();
                nf.setMinimumIntegerDigits(9);
                nf.setGroupingUsed(false);
                final NumberFormat pf = NumberFormat.getPercentInstance();
                pf.setMinimumIntegerDigits(2);
                pf.setGroupingUsed(false);
                // 遍历
                this.STOP_WATCH_MAP.values().forEach(stopWatch -> {
                    StopWatch.TaskInfo lastTaskInfo = stopWatch.getLastTaskInfo();
                    String taskName = lastTaskInfo.getTaskName();
                    long time = lastTaskInfo.getTime(timeUnit);
                    sb.append(nf.format(time)).append("      ");
                    sb.append(pf.format((double) time / totalCost)).append("       ");
                    sb.append(taskName).append(FileUtil.getLineSeparator());
                });
                sb.append("---------------------------------------------").append(FileUtil.getLineSeparator());
            }
            return sb.toString();
        } catch (Exception e) {
            throw new BizException(String.format("打印监控日志失败,原因:%s", e.getCause()), e);
        }
    }
}
